// 存储管理器
// @/utils/storage.ts

import { CryptoUtil } from './crypto'

interface StorageOptions {
  prefix?: string
  encrypt?: boolean
  expire?: number // 默认过期时间（毫秒）
  maxSize?: number // 最大存储大小（字节）
}

interface StorageItem<T = any> {
  data: T
  expire?: number
  timestamp: number
  encrypted?: boolean
}

interface StorageStats {
  keys: string[]
  size: number
  count: number
}

export class StorageManager {
  private prefix: string
  private encrypt: boolean
  private defaultExpire?: number
  private maxSize: number

  constructor(prefix = 'app', options: StorageOptions = {}) {
    this.prefix = options.prefix || prefix
    this.encrypt = options.encrypt || false
    this.defaultExpire = options.expire
    this.maxSize = options.maxSize || 10 * 1024 * 1024 // 默认 10MB
  }

  // 生成完整的键名
  private getKey(key: string): string {
    return `${this.prefix}_${key}`
  }

  // 检查是否为加密数据（简单判断）
  private isEncrypted(data: string): boolean {
    try {
      // 尝试解析 JSON，如果失败说明可能是加密数据
      JSON.parse(data)
      return false
    } catch {
      // 检查是否是 Base64 格式
      return /^[A-Za-z0-9+/]*={0,2}$/.test(data)
    }
  }

  // 设置存储项
  async set<T = any>(
    key: string,
    value: T,
    options?: {
      expire?: number
      encrypt?: boolean
    }
  ): Promise<void> {
    const fullKey = this.getKey(key)
    const shouldEncrypt = options?.encrypt ?? this.encrypt
    
    const item: StorageItem<T> = {
      data: value,
      timestamp: Date.now(),
      encrypted: shouldEncrypt
    }

    if (options?.expire || this.defaultExpire) {
      item.expire = Date.now() + (options?.expire || this.defaultExpire!)
    }

    let dataStr = JSON.stringify(item)
    
    if (shouldEncrypt) {
      dataStr = CryptoUtil.encrypt(dataStr)
    }

    // 检查存储大小
    if (dataStr.length > this.maxSize) {
      throw new Error(`存储项大小超过限制: ${dataStr.length} > ${this.maxSize}`)
    }

    // 检查总存储大小
    await this.checkStorageSize(dataStr.length)

    return new Promise((resolve, reject) => {
      uni.setStorage({
        key: fullKey,
        data: dataStr,
        success: () => resolve(),
        fail: (error) => reject(new Error(error.errMsg))
      })
    })
  }

  // 获取存储项
  async get<T = any>(key: string): Promise<T | null> {
    const fullKey = this.getKey(key)

    return new Promise((resolve) => {
      uni.getStorage({
        key: fullKey,
        success: async (res) => {
          try {
            let dataStr = res.data as string
            
            // 尝试解密
            if (this.isEncrypted(dataStr)) {
              dataStr = CryptoUtil.decrypt(dataStr)
            }

            const item: StorageItem<T> = JSON.parse(dataStr)

            // 检查是否过期
            if (item.expire && Date.now() > item.expire) {
              await this.remove(key)
              resolve(null)
              return
            }

            resolve(item.data)
          } catch (error) {
            console.error('解析存储数据失败:', error)
            resolve(null)
          }
        },
        fail: () => resolve(null)
      })
    })
  }

  // 同步获取
  getSync<T = any>(key: string): T | null {
    try {
      const fullKey = this.getKey(key)
      const dataStr = uni.getStorageSync(fullKey)
      
      if (!dataStr) return null

      let decryptedStr = dataStr
      if (this.isEncrypted(dataStr)) {
        decryptedStr = CryptoUtil.decrypt(dataStr)
      }

      const item: StorageItem<T> = JSON.parse(decryptedStr)

      // 检查是否过期
      if (item.expire && Date.now() > item.expire) {
        this.removeSync(key)
        return null
      }

      return item.data
    } catch (error) {
      return null
    }
  }

  // 设置同步存储
  setSync<T = any>(
    key: string,
    value: T,
    options?: {
      expire?: number
      encrypt?: boolean
    }
  ): void {
    if (options?.encrypt || this.encrypt) {
      throw new Error('同步存储不支持加密')
    }

    const fullKey = this.getKey(key)
    
    const item: StorageItem<T> = {
      data: value,
      timestamp: Date.now()
    }

    if (options?.expire || this.defaultExpire) {
      item.expire = Date.now() + (options?.expire || this.defaultExpire!)
    }

    uni.setStorageSync(fullKey, JSON.stringify(item))
  }

  // 移除存储项
  async remove(key: string): Promise<void> {
    const fullKey = this.getKey(key)
    
    return new Promise((resolve, reject) => {
      uni.removeStorage({
        key: fullKey,
        success: () => resolve(),
        fail: (error) => reject(new Error(error.errMsg))
      })
    })
  }

  // 同步移除
  removeSync(key: string): void {
    const fullKey = this.getKey(key)
    uni.removeStorageSync(fullKey)
  }

  // 清空所有存储
  async clear(): Promise<void> {
    const keys = await this.keys()
    const tasks = keys.map(key => this.remove(key))
    await Promise.all(tasks)
  }

  // 获取所有键
  async keys(): Promise<string[]> {
    return new Promise((resolve) => {
      uni.getStorageInfo({
        success: (res) => {
          const prefix = this.prefix + '_'
          const keys = res.keys
            .filter(key => key.startsWith(prefix))
            .map(key => key.substring(prefix.length))
          resolve(keys)
        },
        fail: () => resolve([])
      })
    })
  }

  // 检查是否存在
  async has(key: string): Promise<boolean> {
    const value = await this.get(key)
    return value !== null
  }

  // 获取存储信息
  async getStats(): Promise<StorageStats> {
    return new Promise((resolve) => {
      uni.getStorageInfo({
        success: (res) => {
          const prefix = this.prefix + '_'
          const keys = res.keys.filter(key => key.startsWith(prefix))
          resolve({
            keys: keys.map(key => key.substring(prefix.length)),
            size: res.currentSize * 1024, // 转换为字节
            count: keys.length
          })
        },
        fail: () => resolve({ keys: [], size: 0, count: 0 })
      })
    })
  }

  // 批量获取
  async getMany<T = any>(keys: string[]): Promise<Record<string, T | null>> {
    const result: Record<string, T | null> = {}
    const tasks = keys.map(async key => {
      result[key] = await this.get<T>(key)
    })
    await Promise.all(tasks)
    return result
  }

  // 批量设置
  async setMany(
    items: Array<{
      key: string
      value: any
      options?: { expire?: number; encrypt?: boolean }
    }>
  ): Promise<void> {
    const tasks = items.map(item =>
      this.set(item.key, item.value, item.options)
    )
    await Promise.all(tasks)
  }

  // 会话存储（应用生命周期内有效）
  private sessionStorage: Map<string, any> = new Map()

  setSession<T = any>(key: string, value: T): Promise<void> {
    this.sessionStorage.set(this.getKey(key), value)
    return Promise.resolve()
  }

  getSession<T = any>(key: string): Promise<T | null> {
    const value = this.sessionStorage.get(this.getKey(key))
    return Promise.resolve(value || null)
  }

  removeSession(key: string): Promise<void> {
    this.sessionStorage.delete(this.getKey(key))
    return Promise.resolve()
  }

  clearSession(): void {
    this.sessionStorage.clear()
  }

  // 加密存储（便捷方法）
  async setSecure<T = any>(key: string, value: T, expire?: number): Promise<void> {
    return this.set(key, value, { expire, encrypt: true })
  }

  async getSecure<T = any>(key: string): Promise<T | null> {
    return this.get<T>(key)
  }

  // 检查存储大小
  private async checkStorageSize(newItemSize: number): Promise<void> {
    const stats = await this.getStats()
    
    if (stats.size + newItemSize > this.maxSize) {
      // 清理过期项
      await this.cleanExpired()
      
      // 再次检查
      const newStats = await this.getStats()
      if (newStats.size + newItemSize > this.maxSize) {
        throw new Error('存储空间不足')
      }
    }
  }

  // 清理过期项
  async cleanExpired(): Promise<number> {
    const keys = await this.keys()
    let cleanedCount = 0

    for (const key of keys) {
      const fullKey = this.getKey(key)
      
      try {
        const dataStr = await new Promise<string | null>((resolve) => {
          uni.getStorage({
            key: fullKey,
            success: (res) => resolve(res.data as string),
            fail: () => resolve(null)
          })
        })

        if (!dataStr) continue

        let decryptedStr = dataStr
        if (this.isEncrypted(dataStr)) {
          decryptedStr = CryptoUtil.decrypt(dataStr)
        }

        const item: StorageItem = JSON.parse(decryptedStr)

        if (item.expire && Date.now() > item.expire) {
          await this.remove(key)
          cleanedCount++
        }
      } catch (error) {
        // 忽略解析错误的项
        await this.remove(key)
        cleanedCount++
      }
    }

    return cleanedCount
  }

  // 更新过期时间
  async touch(key: string, expire: number): Promise<boolean> {
    const value = await this.get(key)
    if (value === null) return false

    await this.set(key, value, { expire })
    return true
  }

  // 获取剩余过期时间
  async ttl(key: string): Promise<number> {
    const fullKey = this.getKey(key)
    
    return new Promise((resolve) => {
      uni.getStorage({
        key: fullKey,
        success: async (res) => {
          try {
            let dataStr = res.data as string
            
            if (this.isEncrypted(dataStr)) {
              dataStr = CryptoUtil.decrypt(dataStr)
            }

            const item: StorageItem = JSON.parse(dataStr)
            
            if (!item.expire) {
              resolve(-1) // 永不过期
            } else {
              const remaining = item.expire - Date.now()
              resolve(remaining > 0 ? remaining : 0)
            }
          } catch {
            resolve(0)
          }
        },
        fail: () => resolve(0)
      })
    })
  }
}

// 创建默认实例
export const storage = new StorageManager()

// 使用示例：
// import { StorageManager } from '@/utils/storage'
//
// const storage = new StorageManager('user')
//
// // 普通存储
// await storage.set('profile', { name: 'John', age: 30 })
// const profile = await storage.get('profile')
//
// // 加密存储
// await storage.setSecure('token', 'secret-token')
// const token = await storage.getSecure('token')
//
// // 设置过期时间（1小时）
// await storage.set('temp', data, { expire: 60 * 60 * 1000 })
//
// // 会话存储
// await storage.setSession('sessionData', data)
// const sessionData = await storage.getSession('sessionData')

// 默认实例便捷方法（保持向后兼容）
export const setStorage = storage.set.bind(storage)
export const getStorage = storage.get.bind(storage)
export const removeStorage = storage.remove.bind(storage)
export const clearStorage = storage.clear.bind(storage) 